# -*- coding: utf-8 -*-
import FPLib
from sqlalchemy import *
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.sql import text
from .Tables import Tables
from .ORMSession import ORMSession

log = FPLib.log("ORM")


class ORM:

    def __init__(self, types=None, conf={}):
        self.config = {
            "echo": FPLib.conf.isdebug,
            "pool_recycle": 3600,
            "max_overflow": 20,
            "pool_size": 5
        }
        self.engine = None
        self.conn = None
        self.DB_CONNECT_STRING = None
        self.isdebug = FPLib.conf.isdebug
        self.tables = {}

        if types is not None:
            if hasattr(self, types):
                call = getattr(self, types)
                if callable(call):
                    call(conf)

    def MySQL(self, conf):
        self.DB_CONNECT_STRING = "mysql+mysqlconnector://{username}:{password}@{host}:{port}/{database}?charset={charset}".format(
            host=conf.get("host", "localhost"),
            port=conf.get("port", 3306),
            database=conf.get("database", ""),
            username=conf.get("username", "root"),
            password=conf.get("password", "root"),
            charset=conf.get("charset", "utf8")
        )
        config = conf.get("config")
        if config:
            self.setConfig(config)
        self.start()

    def SQLite(self, conf):
        self.DB_CONNECT_STRING = "sqlite:///{path}".format(
            path=conf.get("path", ":memory:")
        )
        config = conf.get("config")
        if config:
            self.setConfig(config)
        self.start()

    def setConfig(self, configs):
        self.config.update(configs)

    def start(self, *p, **kw):
        log.debug("ORM start with :", self.DB_CONNECT_STRING)

        if self.DB_CONNECT_STRING is not None:
            self.engine = self.getEngine(*p, **kw)

    def get(self, *p, **kw):
        return self.getSession(*p, **kw)

    def getSession(self, *p, **kw):
        return sessionmaker(bind=self.engine, class_=ORMSession, *p, **kw)()

    def getEngine(self, *p, **kw):
        return create_engine(self.DB_CONNECT_STRING, **self.config)

    def getConn(self):
        if self.conn is None:
            if self.engine is not None:
                self.conn = self.engine.connect()
        return self.conn

    def q(self, sql, *p, **kw):
        result = None
        # sql = sql.format(**p)
        log.debug("execute:", sql)

        if self.engine is not None:
            result = self.engine.execute(text(sql), *p, **kw)
        # print(self.result)
        return result

    def init_db(self):
        # log.debug("init DB ")
        Tables.metadata.create_all(self.engine)

    def drop_db(self):
        Tables.metadata.drop_all(self.engine)

    def reg(self, name, cls):
        self.tables[name] = cls
        # Base.metadata.create_all(engine)
        self.init_db()

    def regTable(self, name, col={}):
        self.reg(name, type(name, (Tables,), col))

    def getTable(self, name):
        return self.tables.get(name, None)

    def __getattr__(self, name):
        return self.getTable(name)
